package ar.edu.caece.pl.alex.manager.impl;

import ar.edu.caece.pl.alex.model.IToken;
import ar.edu.caece.pl.alex.model.impl.Dictionary;
import ar.edu.caece.pl.alex.model.impl.Token;

/**
 * Esta clase es auxiliar al Analizador Lexico
 * Su unico proposito es aliviar la cantidad de codigo del mismo
 * Es por esto que estan muy acopladas: el scope de los metodos del Analizador Lexico
 * son de paquete, asi esta clase los puede utilizar
 */
class ParserHelper {
/* FUNCIONES AUXILIARES DE PARSEO */
	
	/** Q1 y Q2 del Automata ************************************************************/
	IToken reconocerIdsPalabrasReservadas(AnalizadorLexico alex) {
		
		IToken token = new Token(IToken.TYPE_IDENTIFICADOR);
		token.append(alex.getActual());	//Guardo el primero que lei de Q0
		
		boolean sigAlfanumerico = true;	//Miro si el siguiente viene alfanumerico
		
		do {
			switch (alex.getSiguiente().charAt(0)){
				case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
				case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
				case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
				case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': 
				case '6': case '7': case '8': case '9':
					//Viene! entonces avanzo.
					alex.leer();
					token.append(alex.getActual());
					break;
				default:
					
					if(alex.getSiguiente().charAt(0) == '-' && token.getTokenText().equals("end")) {
						
						//Salvar el caso de los end- (if,proc,func)
						alex.leer();
						token.append(alex.getActual());
						break;
						
					} else {						
						sigAlfanumerico = false;
						//Si en el siguiente encuentra "EOF" tambien corta (por la E mayuscula)
						// y retorna el token que viene acumulando
					}
					
			}
		
		} while (sigAlfanumerico);
		
		//Antes de irme reviso si el token acumulado es de casualidad Palabra reservada
		if (Dictionary.getInstance().isValid(token.getTokenText())) {
			
			return new Token(token.getTokenText());
			
		} else {
			
			return token;
		}
	}
	
	
	/** Q3 y Q4 *************************************************************************/
	IToken reconocerComentariosyCadenas(AnalizadorLexico alex) {
		
		IToken token = null;
		
		switch (alex.getActual().charAt(0)) {
			case '{':  token = new Token(IToken.TYPE_COMENTARIO); break;
			case '\'': token = new Token(IToken.TYPE_CADENA); break;
		}
		
		boolean continuar = true;	//condicion de corte
		
		//Como en este caso tengo marca de fin, no tengo que espiar el siguiente.
		
		while(continuar) {
			
			alex.leer();
			switch (alex.getActual().charAt(0)){
				case '}': case '\'':
					token.append(alex.getActual()); //Cierro comment o cadena en el token
					continuar = false;
					break;

				case 'E': //de EOF. recordar que al leer siempre pasamos a minuscula 
						  //pero el fin de archivo lo marcamos en mayuscula.
					//Validar este caso porque deber�a ser un error sint�ctico o semantico, no se si lexico
					token = new Token(IToken.TYPE_ERROR).
						append("Se encontro fin de archivo antes de cerrar comentario");
					continuar = false;
					break;
				
				default:
					//Continuar!
					token.append(alex.getActual());
					break;
			}
		}
		return token;
	}

	/** Q5 - Q14 ***********************************************************************************/
	IToken reconocerOperadores(AnalizadorLexico alex) {
		IToken token = null;
		
		if (alex.getActual().equals(":") && alex.getSiguiente().equals("=")) {
			alex.leer(); //Tengo que adelantar el siguiente y armar el token
			token = new Token(IToken.TYPE_ASIGNACION);
			
		} else if (alex.getActual().equals(":")) {
			token = new Token(IToken.TYPE_DOS_PUNTOS);
			
		} else if (alex.getActual().equals("+") && alex.getSiguiente().equals("+")) {
			alex.leer();
			token = new Token(IToken.TYPE_OPER_MAS_NAT);
			
		} else if (alex.getActual().equals("+")) {
			token = new Token(IToken.TYPE_OPER_MAS_INT);
			
		} else if (alex.getActual().equals("-") && alex.getSiguiente().equals("-")) {
			alex.leer();
			token = new Token(IToken.TYPE_OPER_MENOS_NAT);
			
		} else if (alex.getActual().equals("-")) {
			token = new Token(IToken.TYPE_OPER_MENOS_INT);
		
		} else if (alex.getActual().equals("*") && alex.getSiguiente().equals("*")) {
			alex.leer();
			token = new Token(IToken.TYPE_OPER_MULT_NAT);
			
		} else if (alex.getActual().equals("*")) {
			token = new Token(IToken.TYPE_OPER_MULT_INT);
			
		} else if (alex.getActual().equals("/") && alex.getSiguiente().equals("/")) {
			alex.leer();
			token = new Token(IToken.TYPE_OPER_DIV_NAT);
			
		} else if (alex.getActual().equals("/")) {
			token = new Token(IToken.TYPE_OPER_DIV_INT);
			
		}
		
		return token;
	}
	
	/** Q15 ****************************************************************************************/
	IToken reconocerParentesisCorchetes(AnalizadorLexico alex) {
		IToken token = null;
		switch (alex.getActual().charAt(0)) {
			case '(':  token = new Token(IToken.TYPE_PARENTESIS_IZQ); break;
			case ')': token = new Token(IToken.TYPE_PARENTESIS_DER); break;
			case '[': token = new Token(IToken.TYPE_CORCHETE_IZQ); break;
			case ']': token = new Token(IToken.TYPE_CORCHETE_DER); break;
		}
		return token;
	}

	//El Q16 qued� borrado del dibujo pero no esta actualizado
	//Utilizare la misma numeracion del dibujo
	
	/** Q17 - Q19 **********************************************************************************/ 
	//El '=' lo deje en esta categoria en lugar de Q15 
	IToken reconocerComparadores(AnalizadorLexico alex) {
		
		IToken token = null;
		
		if (alex.getActual().equals("<")) {
		
			//Espiar el siguiente para saber si es <, <= o <>
			switch (alex.getSiguiente().charAt(0)) {
				case '=': 
					alex.leer(); //Tengo que adelantar el siguiente y armar el token
					token = new Token(IToken.TYPE_OPER_MENOR_IGUAL); break;
					
				case '>': alex.leer();
					token = new Token(IToken.TYPE_OPER_DISTINTO); break;
					
				default: //Dejo el siguiente intacto
					token = new Token(IToken.TYPE_OPER_MENOR); break;
			}
			
		} else if (alex.getActual().equals("=")) {
			
			token = new Token(IToken.TYPE_OPER_IGUAL);
			
		} else if (alex.getActual().equals(">")) {
		
			//Espiar el siguiente para saber si es > o >=
			switch (alex.getSiguiente().charAt(0)) {
				case '=': alex.leer(); //Tengo que adelantar el siguiente y armar el token
					token = new Token(IToken.TYPE_OPER_MAYOR_IGUAL); break;
					
				default: //Dejo el siguiente intacto
					token = new Token(IToken.TYPE_OPER_MAYOR); break;
			}
		}
		
		return token;
	}
	
	/** Q23 - Q25 ****************************************************************************/ 
	//La coma y punto-coma los deje en esta categoria
	IToken reconocerSeparadores(AnalizadorLexico alex) {
		
		IToken token = null;
		switch (alex.getActual().charAt(0)) {
			case ',':  token = new Token(IToken.TYPE_COMA); break;
			case ';': token = new Token(IToken.TYPE_PUNTO_COMA); break;
			case ' ': token = new Token(IToken.TYPE_SEPARADOR); break;
			case '\n': token = new Token(IToken.TYPE_SEPARADOR); break;
			case '\t': token = new Token(IToken.TYPE_SEPARADOR); break;
			case '\r': token = new Token(IToken.TYPE_SEPARADOR); break;
			case '\f': token = new Token(IToken.TYPE_SEPARADOR); break;
			case '\b': token = new Token(IToken.TYPE_SEPARADOR); break;
		}
		return token;
	}

	/** Q26 y Q27******************************************************************************/
	IToken reconocerNumeros(AnalizadorLexico alex) {

		IToken token = new Token(IToken.TYPE_NUM_ENTERO);
		token.append(alex.getActual());	//Guardo el primero que lei de Q0
		
		boolean continuar = true;	//Miro si el siguiente viene numero
		
		do {
			switch (alex.getSiguiente().charAt(0)){
				case '0': case '1': case '2': case '3': case '4':
				case '5': case '6': case '7': case '8': case '9':
					//Viene! entonces avanzo.
					alex.leer(); //Avanzar para guardar el actual
					token.append(alex.getActual());
					break;
					
				case 'n':  //Cambiar a numero natural
					alex.leer(); //Avanzar
					token.append(alex.getActual());
					token.setType(IToken.TYPE_NUM_NATURAL);
					continuar = false; //terminar con la "n"
					break;
					
				//case ...
				//TODO Validar si hay que revisar si viene otra cosa que no sea separador y devolver error.
					
				default:
					continuar = false;
					//Si en el siguiente encuentra "EOF" tambien corta (por la E mayuscula)
					// y retorna el token que viene acumulando
			}
		
		} while (continuar);
		
		return token;
	}
	
	/** Trampa **************************************************************************/
	IToken reconocerErrores(AnalizadorLexico alex) {
		return new Token(IToken.TYPE_ERROR).append(alex.getActual());
	}
}
